<?php

if(PARCL_EXEC !== 1) {
    die('<h1>Incorrect Access</h1>You cannot access this file directly.<br/>' .
         'If you got this error message by clicking a link on the site,' .
         'please notify the webmaster as soon as possible.');
}

/**
 * Purpose     : Applies the appropriate templates to the passed data
                 and makes sure that everything surrounding it is in order.
 * Description : Currently is a very crude template application system with only
                 one function and not too much dynamics to anything. Its main
                 purpose currently is to generate valid XHTML output from the specified templates.
 * - Construct -
 * Not defined.
 */

class XSLTemplates {

    /**
     * Input       : $input: The XML file to be parsed by the template system as a string.
                     $params: The parameters to send to the XSLTProcessor to make
                     available for the specified templates.
     * Output      : The output is the complete markup for the curent page in
                     string format ready to be printed.
     * Description : This function is dealing with everything needed to properly
                     convert the XML provided to XHTML/HTML markup through the XSLTProcessor.
     * Errors      : Throws an error if the XSLTProcessor generates an error.
     * Assumptions : That the Registry class is available and that $input is
                     an XML string together with $params being an array.
                     That 'template.xsl' and 'menu.xsl' are available.
     * Dev Notes   : This function needs some major work, specifically in the area
                     of how to dynamically add widgets' styles to the party, but
                     also on how sorting will be processed and how to define widget
                     areas in the style sheet.
     */

    public function Execute($input, $params = null, $extras = array()) {
        $XMLDriver = new XMLDriver();
        $xmlData = $XMLDriver->generate(array('root' => $input));
        $registry = Registry::GetInstance();
        $headers = headers::GetInstance();
        $includeTemplates = $this->getTemplates($registry, $extras);

        $proc = new XSLTProcessor();
        $xsl = new DomDocument('1.0', 'UTF-8');
        $root = $xsl->createElementNS('http://www.w3.org/1999/XSL/Transform', 'xsl:transform');
        $root = $xsl->appendChild($root);
        $root->setAttribute('version', '1.1');
        $browserXml = $xsl->createElementNS('http://www.w3.org/1999/XSL/Transform', 'xsl:output');
        $browserXml = $root->appendChild($browserXml);
        $browserXml->setAttribute('encoding', 'UTF-8');
        if($registry->Get('clientXML')) {
            $browserXml->setAttribute('method', 'xml');
            $browserXml->setAttribute('doctype-system', '-//W3C//DTD XHTML 1.1//EN');
            $browserXml->setAttribute('doctype-public', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd');
            $browserXml->setAttribute('indent', 'yes');
        }
        else {
            $browserXml->setAttribute('method', 'html');
            $browserXml->setAttribute('doctype-system', '-//W3C//DTD XHTML 1.0 Strict//EN');
            $browserXml->setAttribute('doctype-public', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
        }
         foreach($includeTemplates as $template) {
            $include = $xsl->createElementNS('http://www.w3.org/1999/XSL/Transform', 'xsl:include');
            $include = $root->appendChild($include);
            $include->setAttribute('href', $template);
        }
        $proc->importStylesheet($xsl);
        $xml = new DomDocument();
        $xml->loadXML($xmlData);
        $proc->setParameter(null, $params);
        if($output = $proc->transformToXML($xml)) {
            if($registry->Get('clientXML') === true) {
                return $output;
            }
            else {
                $config = array('indent' => true, 'output-xhtml' => true, 'wrap' => 100);
                $tidy = tidy_repair_string($output, $config, 'utf8');
                return $tidy;
            }
        }
        else {
            throw new GeneralException('XSL Transformation failed!', GeneralException::XSL);
        }
    }

    private function getTemplates(Registry $registry, $extras) {
        $scanModules = $registry->Get('ScanModules');
        $templatePath = $registry->Get('templatePath');
        $existingTemplates = $this->scanTemplates($registry);
        $templates = array($templatePath . '/index.xsl');
        foreach($extras as $extra) {
            $templates[] = $templatePath . '/' . $extra . '.xsl';
        }

        $registry->Register('xslModules', $scanModules->ScanFor('template.xsl'));

        foreach($registry->Get('xslModules') as $template) {
            if(in_array($template, $existingTemplates)) {
                $templates[] = $templatePath . '/' . $template . '.xsl';
            }
            else {
                $templates[] = MODULE_DIR . $template . '/template.xsl';
            }
        }

        return $templates;
    }

    /***
     * Returns the templates that already exists in the current template's folder
     * so we don't have to load those templates from the modules.
     */
    private function scanTemplates(Registry $registry) {
        $templateFiles = scandir($registry->Get('templatePath'));
        $templates = array();

        foreach($templateFiles as $file) {
            if(mb_strpos($file, '.xsl')) {
                $templates[] = mb_substr($file, 0, -4);
            }
        }
        return $templates;
    }
}